import json
from decimal import Decimal
import django_redis
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseForbidden
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from apps.goods.models import SKU, SPU
from apps.orders.models import OrderInfo, OrderGoods
from apps.registers.models import Address
from datetime import datetime
import time
from meiduo_mall.settings.dev import logger
from utils.response_code import RETCODE
from django.db import transaction

class OrderSuccessView(LoginRequiredMixin,View):
    def get(self,request):
        order_id = request.GET.get("order_id")
        payment_amount = request.GET.get("payment_amount")
        pay_method = request.GET.get("pay_method")
        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }
        return render(request, 'order_success.html', context)
# 订单保存
class OrderCommitView(LoginRequiredMixin,View):
    """
    1.订单信息需要作持久话保存,所以需要建表保存
    2.两张表,一张是订单基本信息表,还有一张是订单商品表
    3.基本信息和商品表使一对多的关系
    2.前端发送ajax请求.
    """
    def post(self,request):
        """
        保存订单基本信息和订单商品
        当sku表中的库存减少时,销量要增加,同时spu的也要增加
        保存的信息是购物车中选中的商品
        """
        # 1.获取参数
        address_id = json.loads(request.body.decode()).get("address_id")
        pay_method = json.loads(request.body.decode()).get("pay_method")
        # 1.2.校验参数(预处理)
        if not all([address_id,pay_method]):
            return HttpResponseForbidden('参数不能为空')
        try:
            address = Address.objects.get(id= address_id)
        except Address.DoesNotExist:
            return HttpResponseForbidden('参数address_id错误')
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return HttpResponseForbidden('参数pay_method错误')

        user = request.user

        # 构建订单id
        order_id = datetime.now().strftime("%Y%m%d%H%M%S") + ("09%d" % user.id)
        # 设置事务
        with transaction.atomic():
            # 设置回滚点
            save_id = transaction.savepoint()
            # 使用暴力回滚,当一个表出了问题都会进行回滚
            try :
                # 存储数据到订单基本信息表中
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('00.00'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] )
                # 2.完成对订单商品详情表的存储
                # 链接数据库获取到selected为True的全部数据,
                redis_ob = django_redis.get_redis_connection("carts")
                redis_dict = redis_ob.hgetall(user.id)

                # 遍历redis_dict
                total_count = 0
                total_amount = Decimal(0)
                for data in redis_dict.items() :
                    data_selectde = json.loads(data[1].decode())["selected"]
                    # 选择selected为True的商品
                    if data_selectde == True:
                        # 取得sku
                        sku = SKU.objects.get(id = int(data[0].decode()))
                        sku_count = json.loads(data[1].decode())["count"]
                        # 判断如果库存小于销量然会库存不足
                        if sku.stock < sku_count :
                            transaction.savepoint_rollback(save_id)
                            return HttpResponseForbidden("库存不足")
                        # sku表中的库存要减少而销量要增加
                        # 使用乐观锁,保证在修改数据库库存时没有其他客户购买了这个商品
                        # 导致库存不足

                        time.sleep(8)

                        newstock = sku.stock - sku_count
                        newsales = sku.sales + sku_count
                        result = SKU.objects.filter(id = sku.id, stock=sku.stock).update(stock = newstock, sales = newsales)

                        # 判断现在的库存是否还大于购买量,如果大于,从新操作,直到库存不足
                        if result == 0 :
                            continue
                        # spu 表中的销量也要增加
                        spu = SPU.objects.get(id = sku.spu.id)
                        spu.sales += sku_count
                        spu.save()
                        # 构建总价和总数量字段数据
                        total_count += sku_count
                        total_amount += sku_count * sku.price
                        # 构建订单商品表
                        price = sku.price
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=price )
                    # 删除carts中的这条属性
                        redis_ob.hdel(user.id,sku.id)
                # 动态修改数据库数据后记得save()
                order.total_count = total_count
                order.total_amount = total_amount + Decimal('10.00')
                order.save()
            except Exception as f:
                logger.error(f)
                # 一旦上面的代码报错了直接走这边回滚到回滚点
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})
            # 没有失败走这边直接提交事务
            transaction.savepoint_commit(save_id)
        return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})

#  结算订单界面
class OrderView(LoginRequiredMixin,View):
    def get(self,request):
        """
        通过request.user获取到数据库中的数据
        跟据selected为TURE返回对应的数据
        """
        user = request.user
        # 判断收获地址是否为空
        try :
            addresses = Address.objects.filter(user_id = user.id, is_deleted = False)
        # 如果为空返回None,前端判断
        except Address.DoesNotExist:
            addresses = None
        # 链接数据库,获取到全部数据
        redis_ob = django_redis.get_redis_connection("carts")
        redis_dict = redis_ob.hgetall(user.id)
        # 构建前端需要的总数据
        skus = [] #商品列表
        count = 0 #商品总个数
        amount = Decimal(0) #商品总价钱
        # 遍历redis-dict选出selected为TRUE的
        for data in redis_dict.items():
            selected = json.loads(data[1].decode())["selected"]
            if selected == True:
                #返回给前端需要的数据
                sku = SKU.objects.get(id = int(data[0].decode()))
                sku_count = json.loads(data[1].decode())["count"]
                count += sku_count
                amount += sku_count * sku.price
            # 动态添加属性
                sku.count = sku_count
                sku.amount = sku_count * sku.price
                skus.append(sku)
        # 运费
        freight = Decimal('10.00')

        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': count,
            'total_amount': amount,
            'freight': freight,
            'payment_amount': amount + freight
        }

        return render(request,"place_order.html",context)